#ifndef _STRINGUTILS_H
#define _STRINGUTILS_H

#include <iomanip>
#include <sstream>
#include <string>
#include <vector>

#if __APPLE__ || __linux__
#define _In_z_
#define _Printf_format_string_
#define HINSTANCE void*
#define INFINITE -1
#endif

typedef std::string String;
typedef std::wstring WString;
typedef std::vector<String> StringList;
typedef std::vector<WString> WStringList;

class StringUtils {
 public:
  static void Split(const String& s, char delim, std::vector<String>& elems);
  static StringList Split(const String& s, char delim);
  static String Escape(unsigned char ch, bool escapeSafe = true);
  static String Escape(const String& s, bool escapeSafe = true);
  static bool Unescape(const String& s, String& result, bool quoted = true);
  static String Trim(const String& s,
                     const String& delim = StringUtils::WHITESPACE);
  static String TrimLeft(const String& s,
                         const String& delim = StringUtils::WHITESPACE);
  static String TrimRight(const String& s,
                          const String& delim = StringUtils::WHITESPACE);
  static String PadLeft(const String& s, size_t minLength, char ch);
  static String Utf16ToUtf8(const WString& wstr);
  static String Utf16ToUtf8(const wchar_t* wstr);
  static String Utf16ToLocalCp(const WString& wstr);
  static WString Utf8ToUtf16(const String& str);
  static WString Utf8ToUtf16(const char* str);
  static String LocalCpToUtf8(const String& str);
  static String LocalCpToUtf8(const char* str);
  static WString LocalCpToUtf16(const String& wstr);
  static WString LocalCpToUtf16(const char* wstr);
  static void ReplaceAll(String& s, const String& from, const String& to);
  static void ReplaceAll(WString& s, const WString& from, const WString& to);
  static String vsprintf(_In_z_ _Printf_format_string_ const char* format,
                         va_list args);
  static String sprintf(_In_z_ _Printf_format_string_ const char* format, ...);
  static WString vsprintf(_In_z_ _Printf_format_string_ const wchar_t* format,
                          va_list args);
  static WString sprintf(_In_z_ _Printf_format_string_ const wchar_t* format,
                         ...);
  static String ToLower(const String& s);
  static bool StartsWith(const String& str, const String& prefix);
  static bool EndsWith(const String& str, const String& suffix);
  static bool FromHex(const String& text, std::vector<unsigned char>& data,
                      bool reverse = false);
  static String ToHex(unsigned long long value);
  static String ToHex(const unsigned char* buffer, size_t size,
                      bool reverse = false);
  static String ToCompressedHex(const unsigned char* buffer, size_t size);
  static bool FromCompressedHex(const String& text,
                                std::vector<unsigned char>& data);
  static int hackicmp(const char* s1, const char* s2);

  template <typename T>
  static String ToFloatingString(void* buffer) {
    auto value = *(T*)buffer;
    std::stringstream wFloatingStr;
    wFloatingStr << std::setprecision(std::numeric_limits<T>::digits10)
                 << value;
    return wFloatingStr.str();
  }

  template <typename T>
  static String ToIntegralString(void* buffer) {
    auto value = *(T*)buffer;
    return ToHex(value);
  }

 private:
  static const String WHITESPACE;
};

#endif  //_STRINGUTILS_H
